package http

import (
	"errors"
	"fmt"
	"github.com/sirupsen/logrus"
	"micro-oauth/datamodels"
	"micro-oauth/hexerror"
	"micro-oauth/libs"
	"micro-oauth/rpcservice"
	"micro-oauth/utils"
	"strings"

	"github.com/gin-gonic/gin"
	"micro-oauth/service"
	"net/http"
)

type RegPostParams struct {
	Username     string `form:"username" json:"username" binding:"required"`
	Password     string `form:"password" json:"password" binding:"required"`
	Telephone    string `form:"telephone" json:"telephone" binding:"required"`
	AuthCode  string `form:"authCode" json:"authCode" binding:"required"`
}

type LoginGetParams struct {
	ClientId     string `form:"client_id" json:"client_id" binding:"required"`
	Scope        string `form:"scope" json:"scope" binding:"required"`
	State        string `form:"state" json:"state"`
	RedirectURI  string `form:"redirect_uri" json:"redirect_uri"`
	ResponseType string `form:"response_type" json:"response_type"`
}

type LoginPostParams struct {
	LoginGetParams
	UserName   string `form:"username" json:"username" binding:"required"`
	Password   string `form:"password" json:"password"`
	DeviceUUID string `form:"device_uuid" json:"device_uuid"`
}

func (p *LoginPostParams) Validate() error {
	if p.ClientId == "" {
		return errors.New("ClientId Needed")
	}
	if p.RedirectURI == "" {
		return errors.New("RedirectURI Needed")
	}
	if p.Scope == "" {
		return errors.New("Scope Needed")
	}
	//if p.ResponseType == "" {
	//	return errors.New("ResponseType Needed")
	//}
	p.UserName = strings.Trim(p.UserName, " \t\n")
	if p.UserName == "" {
		return errors.New("用户名必填！")
	}
	if p.Password == "" {
		return errors.New("密码必填！")
	}
	return nil
}

func PingGet(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"message": "pong",
	})
}

//获取验证码
func GetCode(c *gin.Context) {
	telephone :=c.Query("telephone")
	code := libs.GenValidateCode(6)
	result := map[string]interface{}{
		//"token": gin.H{
		//				"access_token":  "token.AccessToken",
		//				"refresh_token": "token.RefreshToken",
		//				},
		"code": code,
	}
	service.CacheService.SetRegCode(telephone,code)
	c.JSON(http.StatusOK, libs.ReturnJson(200, "", result))
	return
}

//注册
func OauthRegister(c *gin.Context) {
	var params RegPostParams
	c.ShouldBind(&params)
	//1、效验验证码
	code := params.AuthCode
	redisCode := service.CacheService.GetRegCode(params.Telephone)
	fmt.Println("code",code)
	fmt.Println("redisCode",redisCode)
	if code == redisCode {
		//调用用户rpc服务进行注册
		var user datamodels.User
		user.Name = params.Username
		user.Password = params.Password
		user.Phone = params.Telephone
		rpcservice.MemberService.Register(&user)
		c.JSON(http.StatusOK, libs.ReturnJson(200, "注册成功", "success"))
		return
	}else{
		c.JSON(http.StatusOK, libs.ReturnJson(200, "验证码错误", "success"))
		return
	}
}

//获取用户信息
func GetUserInfo(c *gin.Context) {
	 result,err := rpcservice.MemberService.GetUserInfo()
	 //返回结果是[]byte
	//fmt.Printf("res的数据类型为：%v\n", reflect.TypeOf(result))
	if err == nil {
		c.JSON(http.StatusOK, libs.ReturnJson(200, "", result))
	}else{
		c.JSON(http.StatusOK, libs.ReturnJson(402, "", err.Error()))
	}
	return
}

func OauthLoginGet(c *gin.Context) {
	access_token :=c.Query("access_token")
	if access_token == "" {
		var params LoginGetParams
		_ = c.ShouldBindQuery(&params)
		data := gin.H{
			"error":  nil,
			"Params": params,
			"domain": GetHost(c.Request),
		}

		c.HTML(http.StatusOK, "login.html", data)
	}else {
		fmt.Println("登录token:",access_token)
		//expires_in :=c.Query("expires_in")
		//expiration, err := strconv.Atoi(expires_in)
		_, _, token, err := service.OauthService.UserLogin(
			"g63PPs_biVRTibAZydgSuXjtUjYvFa1ntgusrdd",
			"liweihao",
			"liweihao!123",
			"hex",
			"hex-server",
			"https://pos-test-api.heytea.com",
			"",
		)
		fmt.Println("new token:",token)
		c.Redirect(302, "http://localhost:9091/#/?access_token="+access_token)
		if err != nil {
			//c.Redirect(302, "/oauth2/oauth/api/v1/ping")
			c.Redirect(302, "http://localhost:9091/#/my/task")
		}
	}

}

func OauthLoginPost(c *gin.Context) {
	header := c.NegotiateFormat("application/json")
	logrus.Info("header:",header)
	if c.NegotiateFormat("application/json") == "application/json" {
		utils.PDALoginTimes.Inc()
		utils.LoginTimes.Inc()
		OauthLoginPOSTAPI(c)
	} else {
		utils.WebLoginTimes.Inc()
		utils.LoginTimes.Inc()
		OauthLoginPostHTML(c)
	}
}

func OauthLoginPostHTML(c *gin.Context) {
	var params LoginPostParams
	_ = c.ShouldBind(&params)
	err := params.Validate()
	data := gin.H{
		"Params": params,
		"domain": c.Request.Host,
	}
	if err != nil {
		data["error"] = err.Error()
		c.HTML(http.StatusBadRequest, "login.html", data)
		return
	}
	_, _, token, err2 := service.OauthService.UserLogin(
		params.ClientId, params.UserName, params.Password, params.State,
		params.Scope, params.RedirectURI, params.DeviceUUID,
	)
	if err2 != nil {
		data["error"] = err2.Description()
		c.HTML(http.StatusBadRequest, "login.html", data)
		return
	}
	c.Redirect(http.StatusFound, params.RedirectURI+"#/?"+token.ToQueryString())
	return
}

func OauthLoginPOSTAPI(c *gin.Context) {
	var params LoginPostParams
	_ = c.ShouldBindJSON(&params)
	//if params.DeviceUUID == "197118B00207756" {
		logrus.Warnf("params:%v",params)
	//}
	err := params.Validate()
	if err != nil {
		hexerr := hexerror.InvalidData(err.Error())
		c.JSON(http.StatusOK, HexErrorToResponse(hexerr))
		return
	}
	_, _, token, err2 := service.OauthService.UserLogin(
		params.ClientId, params.UserName, params.Password, params.State, params.Scope,
		params.RedirectURI, params.DeviceUUID,
	)
	if err2 != nil {
		c.JSON(http.StatusOK, HexErrorToResponse(err2))
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"status_code": SuccessCode,
		"payload": gin.H{
			"access_token":  token.AccessToken,
			"refresh_token": token.RefreshToken,
		},
	})
	return
}

func GetHost(req *http.Request) string {
	host1 := getValueFromHeader("Host", req.Header)
	host2 := getValueFromHeader("X-Forwarded-Host", req.Header)
	if host1 != "" {
		return host1
	}
	return host2
}

func getValueFromHeader(name string, header http.Header) string {
	headerValues := header[name]
	if len(headerValues) == 0 {
		return ""
	}
	return headerValues[0]
}
